/*
 * 文件名称：AppTimer.cpp
 * 文件描述：提供应用程序定时功能，并执行定时回调函数
 * 作者信息：Satan-Emperor
 * 版本信息：V1.0.0
 * 修改历史：2014-04-22
 */

#include "AppTimer.h"
#include "debugLog.h"
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

/* 取绝对值宏 */
#define ABS(x) ((x)<0 ? -(x) : (x))

/* 每次滴答的微秒时间 */
#define CPU_TICK_USEC	(100000)

/*
 * 类名称：AppTimerCompare
 * 类描述：通过括号重载符比较输入类中的成员变量与本类中的成员变量，并返回结果值
 * 类说明：用于remove_if函数中，无需单独定义类，直接用即可，这是remove_if的特性
 */
class AppTimerCompare
{
private:
    int mTimerId;

public:
    AppTimerCompare(int timerId) : mTimerId(timerId)
    {
    }
    bool operator()(TimerInfo &timerInfo)
    {
        return (timerInfo.timerId == mTimerId);
    }
};

/*
 * 函数名称：AppTimer
 * 函数描述：构造AppTimer，初始化变量并创建线程
 * 输入参数：无
 * 输出参数：无
 * 其他说明：因为有多个程序访问，必须加入互斥锁
 */
AppTimer::AppTimer(void)
{
    pthread_mutex_init(&mTimerMutex, NULL);
    pthread_mutex_init(&mCpuTickMutext, NULL);

    memset(mTimerIdPool, 0x00, sizeof(mTimerIdPool));
    mTimerList.clear();

    mTimerThread.createThread(1, 1, 16*1024, timerThreadFunc, this);
}

/*
 * 函数名称：~AppTimer
 * 函数描述：析构AppTimer，销毁互斥锁
 * 输入参数：无
 * 输出参数：无
 * 其他说明：必须销毁互斥锁，以防内存泄漏
 */
AppTimer::~AppTimer(void)
{
    pthread_mutex_destroy( &mTimerMutex );
    pthread_mutex_destroy( &mCpuTickMutext );
}

/*
 * 函数名称：setTimer
 * 函数描述：设置定时器，相当于创建一个定时器
 * 输入参数：1.timerId，定时器标识，可自动获取；
 *			 2.type，一次或间歇定时；
 *			 3.elapse，定时时间；
 *			 4.handle，定时器到执行的函数指针；
 *			 5.pParam，参数
 * 输出参数：1. int，执行结果
 * 其他说明：时钟滴答和定时时间都以毫秒计算
 */
int AppTimer::setTimer(int timerId, int type, int elapse, TimerHandle handle, void *pParam)
{
    int id = -1;
    if (timerId == TIMER_ID_AUTO)
    {
        id = getTimerId();
    }
    else
    {
        if (mTimerIdPool[timerId].state == 1)
        {
            // The timer is already in use
            return -1;
        }
        else
        {
            id = timerId;
        }
    }

    pthread_mutex_lock( &mTimerMutex );

    mTimerList.remove_if(CAppTimerCompare(timerId));

    TimerInfo timerInfo;
    timerInfo.timerId = id;
    timerInfo.type = type;
    timerInfo.baseTime = getCpuTick();
    timerInfo.elapse = (uint64_t )(elapse / 100);
    timerInfo.handle = handle;
    timerInfo.pParam = pParam;
    mTimerList.push_back( timerInfo );

    pthread_mutex_unlock( &mTimerMutex );

    return 0;
}

/*
 * 函数名称：resetTimer
 * 函数描述：复位定时器，实为将刷新定时器的基准时间
 * 输入参数：1.timerId，定时器标识；
 * 输出参数：1.int，执行结果
 * 其他说明：记得使用互斥锁，以免数据竞争
 */
int AppTimer::resetTimer(int timerId)
{
    if (timerId > MAX_TIMER_CNT) 
    {
        DEBUG_ERROR(COMMON_LIB, "timerId error");
        return -1;
    }

    std::list<TimerInfo>::iterator it;

    pthread_mutex_lock( &mTimerMutex );

    for (it = mTimerList.begin(); it != mTimerList.end(); it++)
    {
        if (it->timerId == timerId)
        {
            it->baseTime = getCpuTick();
            break;
        }
    }

    pthread_mutex_unlock( &mTimerMutex );

    return 0;
}

/*
 * 函数名称：killTimer
 * 函数描述：销毁定时器，将定时器ID从链表中移除
 * 输入参数：1.timerId，定时器标识；
 * 输出参数：1.int，执行结果
 * 其他说明：记得使用互斥锁，以免数据竞争取；记得将定时器池中的状态置0
 */
int AppTimer::killTimer(int timerId)
{
    mTimerIdPool[timerId].state = 0;

    pthread_mutex_lock( &mTimerMutex );
    mTimerList.remove_if(AppTimerCompare(timerId));
    pthread_mutex_unlock( &mTimerMutex );

    return 0;
}

/*
 * 函数名称：run
 * 函数描述：销毁定时器，将定时器ID从链表中移除
 * 输入参数：无
 * 输出参数：无
 * 其他说明：当执行失败的时候，为什么要++it？
 */
void AppTimer::run(void)
{
    std::list<TimerInfo>::iterator it;
    uint64_t curTime = getCpuTick();

	pthread_mutex_lock( &mTimerMutex );
    for (it = mTimerList.begin(); it != mTimerList.end(); it++)
    {
        if (ABS(curTime - it->baseTime) >= it->elapse)
        {
            /* 定时时间到，执行回调函数 */
            if (it->handle(it->timerId, it->pParam) == false )
            {
                std::list<TimerInfo>::iterator it2 = it;
                ++it;
                mTimerList.remove_if(AppTimerCompare(it2->timerId));
            }
            else
            {
                it->baseTime = curTime;
            }
        }
    }
	pthread_mutex_unlock( &mTimerMutex );
}

/* 
 * 函数名称：getTimerId
 * 函数描述：获取空闲的定时器，并返回id
 * 输入参数：无
 * 输出参数：1.id，定时器id；2.如果返回值为-1则失败
 * 其他说明：
 */
int AppTimer::getTimerId(void)
{
    int i = 0;
    for (i = 0; i < MAX_TIMER_CNT; i++)
    {
        if (mTimerIdPool[i].state == 0)
        {
            mTimerIdPool[i].state = 1;
            return mTimerIdPool[i].id;
        }
    }

    return -1;
}

/* 
 * 函数名称：getCpuTick
 * 函数描述：获取时钟滴答
 * 输入参数：无
 * 输出参数：1.cpuTick，时钟滴答数
 * 其他说明：时钟滴答在另外一个函数中累加，获取需加锁
 */
uint64_t AppTimer::getCpuTick(void)
{
    uint64_t cpuTick = 0;

    pthread_mutex_lock(&mCpuTickMutext);
    cpuTick = mCpuTick;
    pthread_mutex_unlock(&mCpuTickMutext);

    return cpuTick;
}

/* 
 * 函数名称：timerThreadFunc
 * 函数描述：定时器线程，主要用于时钟滴答的累加
 * 输入参数：1.param，类指针
 * 输出参数：1.void指针，线程指针
 * 其他说明：时钟滴答被其他程序调用，需加互斥锁
 */
void *AppTimer::timerThreadFunc(void *param)
{
    AppTimer *pThis = (AppTimer * )param;

    pThis->mCpuTick = 0;

    DEBUG_INFO(COMMON_LIB, "Enter cpu tick thread");

    while (1)
    {
        usleep(CPU_TICK_USEC);

        pthread_mutex_lock(&pThis->mCpuTickMutext);
        ++pThis->mCpuTick;
        pthread_mutex_unlock(&pThis->mCpuTickMutext);
    }

    pThis->mTimerThread.exitThead();

    return NULL;
}

/* 
 * 函数名称：getmSecond
 * 函数描述：获取系统时间的毫秒数
 * 输入参数：无
 * 输出参数：1.msec，系统时间的毫秒数，long long类型
 * 其他说明：需算上时区偏移和毫秒项，此为1970到现在的毫秒数
 */
long long AppTimer::getmSecond(void)
{
    long long msec = 0;
    struct timeval tv;
    struct timezone tz;
    gettimeofday( &tv, &tz);

    msec += (long long)tv.tv_sec * 1000;
    msec += (long long)tz.tz_minuteswest * 60 * 1000;
    msec += (long long)tv.tv_usec / 1000;

    return msec;
}

/* 
 * 函数名称：getSecond
 * 函数描述：获取系统时间的秒数
 * 输入参数：无
 * 输出参数：1.sec，系统时间的秒数
 * 其他说明：需算上时区偏移项，此为1970年到现在的秒数
 */
time_t AppTimer::getSecond(void)
{
    struct timeval tv;
    struct timezone tz;
    gettimeofday( &tv, &tz);
    return tv.tv_sec + tz.tz_minuteswest * 60;
}

// EOF
